function [str, cell_str, s] = struct2str(s, disp_str, index_of_fields_to_use, x_ratio, y_ratio)
% STRUCT2STR - Converts a struct into a char string and optionally display
% its pairs of field names and field values in a list box.
% The rows of the list box visualizing the fields can be individually
% selected, and the corresponding fields can be copied to the clipboard.
% In this way, this function can be used to paste significant fields
% of a struct to a plain text file, for documentation purposes.
% By displaying the obtained char string we get a similar output as
% the one generated by the Matlab built-in function DISP, when called on the original struct.
% 
% INPUTS:
% s: the struct to be converted and optionally visualized
% disp_str: When disp_str = 1 a listbox is shown containing the string provided after the conversion of the input struct
% index_of_fields_to_use: this is vector containing the indices of the fields to convert to string
% xratio: is the normalized width of the listbox with respect to the width of the screen 
% yratio: is the normalized height of the listbox with respect to the height of the screen
%
% OUTPUTS:
% str: the char string obtained after the conversion of the input struct s
% cell_str: this is a cell of string. Each cell contains a pair
% (field_name, field_value)
% s: the input struct is also returned as an output.
%
% % Example 1
%     disp('-------------------------------------------------------');
%     s.field1 = 'This is the first field of an example struct';
%     s.field2 = 35;
%     s.field3 = [ 1 2 3 4 5];
%     s.field4 = cell(4,2);
%     s.field5 = {'first_char_item','second_char_item','third_char_item'};
%     s.field6 = {[1 2 3], [4 5 6], [7 8]};
%     s.field7 = ones(10,4);
%     s.field8 = 'First unused field';    
%     s.field9 = 'Second unused field';    
%     
%     disp_str = 1;
%     index_of_fields_to_use = 1:7;
%     s_title = 'The s struct';
%     s_name = 's';
%     [str, cell_str, s] = struct2str(s, disp_str, index_of_fields_to_use);
%     % In case you pressed 'Copy selected fields to clipboard ...', you can now paste 
%     % the struct description on a plain text file.
%     disp('-------------------------------------------------------');
%     disp(s);
%     disp(str); 
%     disp('The last two instructions should provide similarly formatted outputs on the first seven fields of s.');
%     disp('-------------------------------------------------------');

% See also STRUCT2CELL, STRUCT2ARRAY, CELL2STRUCT, FIELDNAMES.

% STRUCT2STR, $Version: 1.0, May 2007
% Author: Marco Cococcioni
% Please report any bug to m.cococcioni <at> gmail.com

if nargin < 5,
    y_ratio = 0.5;
end

if nargin < 4,
    x_ratio = 0.5;
end

if nargin < 2,
    disp_str = 0;
end

if nargin < 1,
    s.field1 = 'This is the first field of an example struct';
    s.field2 = 35;
    s.field3 = [ 1 2 3 4 5];
    s.field4 = cell(4,2);
    s.field5 = {'first_char_item','second_char_item','third_char_item'};
    s.field6 = {[1 2 3], [4 5 6], [7 8]};
    s.field7 = ones(10,4);
    s.field8 = 'First unused field';    
    s.field9 = 'Second unused field';    
    
    disp_str = 1;
    index_of_fields_to_use = 1:7;
    s_title = 'The s struct';
    s_name = 's';
    [str, cell_str, s] = struct2str(s, disp_str, index_of_fields_to_use);
    return    
else
    s_title = sprintf('The %s struct',inputname(1));
    s_name  = inputname(1);
end

len = length(s);
fnames = fieldnames(s(1));

if nargin < 3,
    index_of_fields_to_use = 1:length(fnames);
elseif isempty(index_of_fields_to_use),
    index_of_fields_to_use = 1:length(fnames);
end
    

str = '';

k = 1;

max_len = 0;
for l = 1:len
    for f = 1:length(fnames)
        l = length(fnames{f});
        if l > max_len,
            max_len = l;
        end
    end
end

max_len = max_len + length(s_name) + 3;

fmt1  = sprintf('%%s%%%ds: %%s\n', max_len);
fmt2 =  sprintf('%%s%%%ds: [%%dx%%d double]\n', max_len);
fmt3 =  sprintf('%%s%%%ds: {%%dx%%d cell}\n', max_len);
fmt4 =  sprintf('%%s%%%ds: [%%dx%%d %%s]\n', max_len);

fmt11  = sprintf('%%%ds: %%s\n', max_len);
fmt22 =  sprintf('%%%ds: [%%dx%%d double]\n', max_len);
fmt33 =  sprintf('%%%ds: {%%dx%%d cell}\n', max_len);
fmt44 =  sprintf('%%%ds: [%%dx%%d %%s]\n', max_len);

for l = 1:len
    for f = 1:length(fnames)
      
        if not(isempty(find(f == index_of_fields_to_use))),

            [nr,nc] = size(getfield(s,{l},fnames{f}));
            
            if ischar(getfield(s,{l},fnames{f}))
                str = sprintf(fmt1,str,fnames{f}, [ '''' getfield(s,{l},fnames{f}) ''''] );
                cell_str{k} = sprintf(fmt11,fnames{f},[ '''' getfield(s,{l},fnames{f}) ''''] );
                k = k + 1;
            elseif isnumeric(getfield(s,{l},fnames{f}))
                if (max(nr,nc) < 9 && min(nr,nc)==1)
                    if nr==1 && nc == 1,
                        str = sprintf(fmt1,str,fnames{f}, num2str(getfield(s,{l},fnames{f})));
                        cell_str{k} = sprintf(fmt11,fnames{f}, num2str(getfield(s,{l},fnames{f})));
                        k = k + 1;                                           
                    else
                        str = sprintf(fmt1,str,fnames{f}, [ '[' num2str(getfield(s,{l},fnames{f})) ']' ]);
                        cell_str{k} = sprintf(fmt11,fnames{f}, [ '[' num2str(getfield(s,{l},fnames{f})) ']' ] );
                        k = k + 1;                
                    end
                else
                    str = sprintf(fmt2,str,fnames{f},nr,nc);
                    cell_str{k} = sprintf(fmt22,fnames{f},nr,nc);
                    k = k + 1;
                end
            elseif iscell(getfield(s,{l},fnames{f})),
                if (max(nr,nc) < 9 && min(nr,nc)==1),
                    d = getfield(s,{l},fnames{f});
                    d = d(:)';
                    if ischar(d{1}),
                        m = 2;
                        while m <= length(d) && (ischar(d{m})),
                            m = m + 1;
                        end
                        if m - 1 == length(d),
                            d_str = '{';
                            for n=1:m-2,
                                d_str = sprintf('%s''%s''  ',d_str,d{n});
                            end
                            d_str = sprintf('%s''%s''}',d_str,d{m-1});
                            str = sprintf(fmt1,str,fnames{f},d_str);
                            cell_str{k} = sprintf(fmt11,fnames{f},d_str);
                            k = k + 1;
                        end
                    elseif isnumeric(d(1)),
                        error DA_TERMINARE!
                        keyboard
                    else
                        str = sprintf(fmt3,str,fnames{f},nr,nc);
                        cell_str{k} = sprintf(fmt33,fnames{f},nr,nc);
                        k = k + 1;
                    end
                else
                    str = sprintf(fmt3,str,fnames{f},nr,nc);
                    cell_str{k} = sprintf(fmt33,fnames{f},nr,nc);
                    k = k + 1;
                end
            else
                str = sprintf(fmt4,str,fnames{f},nr,nc,class(getfield(s,{l},fnames{f})));
                cell_str{k} = sprintf(fmt44,fnames{f},nr,nc,class(getfield(s,{l},fnames{f})));
                k = k + 1;
            end
        end
    end
end

if disp_str,
    clipboard('copy',str);
    screen_size = get(0,'ScreenSize');
    [ind, ok] = listdlg('ListString',cell_str,'OKString','Copy selected fields to clipboard and quit','ListSize',[x_ratio*screen_size(3), y_ratio*screen_size(4)],'name',s_title, 'InitialValue', 1:length(cell_str));
    if ok,      
        clipboard('copy', sprintf('%s = \n%s', s_name, cat(2,cell_str{ind})));
    end
end
